package me.chinaq.fastweb;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import me.chinaq.fastweb.dao.BaseDao;
import me.chinaq.fastweb.web.CounterHandler;
import me.chinaq.fastweb.web.XssStringJsonSerializer;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.boot.Banner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.socket.config.annotation.*;

import java.util.Properties;

import static me.chinaq.fastweb.ProjectConstant.MAPPER_PACKAGE;


//开启异步方法调用
@EnableAsync
//开启定时任务扫描
@EnableScheduling
//Mybatis扫描包
@MapperScan(value = MAPPER_PACKAGE, markerInterface = BaseDao.class)
//扫描Servlet3.0
//@ServletComponentScan
@SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {

	public static void main(String[] args) {
		new SpringApplicationBuilder(Application.class).bannerMode(Banner.Mode.OFF).run(args);
	}

	/**
	 * 添加拦截器
	 *
	 * @param registry
	 */
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		//registry.addInterceptor(new FastInterceptor());
	}

	//platformTransactionManager 为springboot默认初始化好的对象，，无需定义
	//这里不能再取名叫transactionInterceptor，
	// 因为springboot会通过ProxyTransactionManagementConfiguration自动加载一个叫transactionInterceptor的拦截器， 覆盖掉这里定义的拦截器，导致自定义拦截不起作用
	@Bean(name = "myTransactionInterceptor")
	public TransactionInterceptor transactionInterceptor(PlatformTransactionManager platformTransactionManager) {
		TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
		// 事物管理器
		transactionInterceptor.setTransactionManager(platformTransactionManager);
		Properties transactionAttributes = new Properties();
		transactionAttributes.setProperty("select*", "PROPAGATION_SUPPORTS,readOnly");
		transactionAttributes.setProperty("*", "ISOLATION_REPEATABLE_READ,PROPAGATION_REQUIRED");
		transactionInterceptor.setTransactionAttributes(transactionAttributes);
		return transactionInterceptor;
	}

	//代理到ServiceImpl的Bean
	@Bean
	public BeanNameAutoProxyCreator transactionAutoProxy() {
		BeanNameAutoProxyCreator transactionAutoProxy = new BeanNameAutoProxyCreator();
		transactionAutoProxy.setProxyTargetClass(true);
		transactionAutoProxy.setBeanNames("*ServiceImpl");
		transactionAutoProxy.setInterceptorNames("myTransactionInterceptor");
		return transactionAutoProxy;
	}

	/**
	 * 处理json请求的xss攻击
	 *
	 * @return
	 */
	@Bean
	public ObjectMapper xssObjectMapper() {
		//注册xss解析器
		SimpleModule xssModule = new SimpleModule().addSerializer(new XssStringJsonSerializer());
		//解析器
		ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
		objectMapper.registerModule(xssModule);
		//返回
		return objectMapper;
	}

}

//开启WebSocket
@EnableWebSocket
//同下面的WebSocketMessageBrokerConfig只能二者取其一
@Configuration
class WebSocketConfig implements WebSocketConfigurer {
	/**
	 * 注册处理类
	 *
	 * @param webSocketHandlerRegistry
	 */
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
		//指定counterHandler处理/counter的请求
		webSocketHandlerRegistry.addHandler(counterHandler(), "/counter").setHandshakeHandler(new CounterHandler.FastDefaultHandshakeHandler())
				//添加WebSocket握手请求的拦截器.
				.addInterceptors(new CounterHandler.CountHandshakeInterceptor());
		//添加对socketjs的支持
		webSocketHandlerRegistry.addHandler(counterHandler(), "/counter")
				//添加WebSocket握手请求的拦截器.
				.addInterceptors(new CounterHandler.CountHandshakeInterceptor()).withSockJS();
	}

	@Bean
	public CounterHandler counterHandler() {
		return new CounterHandler();
	}
}

//开启WebSocket，并启用 STOMP
@EnableWebSocketMessageBroker
//@Configuration
class WebSocketMessageBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer {

	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
		//将“/register”注册为STOMP端点,客户端在订阅或发布消息到目的地路径前，要连接该端点
		registry.addEndpoint("/register").setHandshakeHandler(new CounterHandler.FastDefaultHandshakeHandler()).addInterceptors(new CounterHandler.CountHandshakeInterceptor());
		registry.addEndpoint("/register").setHandshakeHandler(new CounterHandler.FastDefaultHandshakeHandler()).addInterceptors(new CounterHandler.CountHandshakeInterceptor()).withSockJS();

	}

	@Override
	public void configureMessageBroker(MessageBrokerRegistry config) {
		//客户端发送消息的请求前缀
		config.setApplicationDestinationPrefixes("/ws");
		//客户端订阅消息的请求前缀
		config.enableSimpleBroker("/topic", "/queue");
		//服务端通知客户端的前缀
		config.setUserDestinationPrefix("/user");
	}

	@Override
	public void configureClientOutboundChannel(ChannelRegistration registration) {
		registration.setInterceptors(new ChannelInterceptorAdapter() {
			@Override
			public Message<?> preSend(Message<?> message, MessageChannel channel) {
				System.out.println("send: " + message);
				return super.preSend(message, channel);
			}
		});
	}
}